package net.yla.smartbus.core.util;

import com.vip.vjtools.vjkit.time.DateUtil;
import org.joda.time.*;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * 时间工具类
 *
 * @author ZengXiaoLiang
 * @date 2018/6/11 20:15
 */
public class JodaDateUtil {
    public static final String YYYY_MM_DD_HH_MM_SS_DASH = "yyyy-MM-dd HH:mm:ss";
    public static final String YYYYMMDD_HH_MM_SS_DASH_BROKEN = "yyyy/MM/dd HH:mm:ss";

    /**
     * 查询指定日期的上月的开始时间与结束时间 ZengXiaoLiang 2016年6月13日 下午5:04:48
     *
     * @param currDate
     * @return
     */
    public static Date[] getLastMonthStartAndEndDate(Date currDate) {
        Date[] dates = new Date[2];
        DateTime dt = new DateTime(currDate).minusMonths(1);
        DateTime start = new DateTime(dt.getYear(), dt.getMonthOfYear(), 1, 0, 0, 0);
        dates[0] = start.toDate();
        DateTime end = new DateTime(dt.getYear(), dt.getMonthOfYear(), dt.dayOfMonth().getMaximumValue(), 23, 59, 59);
        dates[1] = end.toDate();
        return dates;
    }

    /**
     * @author ZeyangWu
     * @date 2017年5月5日下午2:58:02
     * @Description: 根据当前时间获取上周日期区域
     */
    public static Date[] getLastWeekStartAndEndDate(Date currDate) {
        Date[] dates = new Date[2];
        DateTime dt = new DateTime(currDate).minusWeeks(1);
        DateTime start = dt.minusDays(dt.getDayOfWeek() - 1).withTimeAtStartOfDay().toDateTime();
        DateTime end = dt.plusDays(8 - dt.getDayOfWeek()).withTimeAtStartOfDay().toDateTime();
        dates[0] = start.toDate();
        dates[1] = end.toDate();
        return dates;
    }

    /**
     * 查询指定日期一天的开始时间。时分秒为 00:00:00 ZengXiaoLiang 2016年9月27日 下午12:38:11
     *
     * @param date
     * @return
     */
    public static Date getStartDate(Date date) {
        DateTime dt = new DateTime(date).withTimeAtStartOfDay();
        return dt.toDate();
    }

    /**
     * 查询指定日期的一天的结束时间 ZengXiaoLiang 2016年9月27日 下午1:01:04
     *
     * @param date
     * @return
     */
    public static Date getEndDate(Date date) {
        DateTime dt = new DateTime(date).plusDays(1).withTimeAtStartOfDay().minusSeconds(1);
        return dt.toDate();
    }

    /**
     * 增加天数 ZengXiaoLiang 2016年10月24日 上午11:26:40
     *
     * @param date
     * @param days
     * @return
     */
    public static Date
    plusDays(Date date, int days) {
        return new DateTime(date).plusDays(days).toDate();
    }

    /**
     * 增加小时 ZengXiaoLiang 2017年2月28日 下午2:07:32
     *
     * @param date
     * @param hours
     * @return
     */
    public static Date plusHours(Date date, int hours) {
        return new DateTime(date).plusHours(hours).toDate();
    }

    /**
     * 增加分钟 ZengXiaoLiang 2017年3月31日 下午3:19:44
     *
     * @param date
     * @param minutes
     * @return
     */
    public static Date plusMinutes(Date date, int minutes) {
        return new DateTime(date).plusMinutes(minutes).toDate();
    }

    /**
     * 增加秒数
     *
     * @param date
     * @param second
     * @return
     */
    public static Date plusSecond(Date date, int second) {
        return new DateTime(date).plusSeconds(second).toDate();
    }

    /**
     * 使用默认格式解析 yyyy-MM-dd HH:mm:ss
     *
     * @param datetime
     * @return
     */
    public static Date parseStr2Date(String datetime) {
        String pattern;
        String monthRegex = "^(\\d{4})-([0-1]\\d)$";
        String dayRegex = "^(\\d{4})-([0-1]\\d)-([0-3]\\d)$";
        String hourRegex = "^(\\d{4})-([0-1]\\d)-([0-3]\\d)\\s([0-5]\\d)$";
        String minRegex = "^(\\d{4})-([0-1]\\d)-([0-3]\\d)\\s([0-5]\\d):([0-5]\\d)$";
        if (datetime.matches(monthRegex)) {
            pattern = "yyyy-MM";
        } else if (datetime.matches(dayRegex)) {
            pattern = "yyyy-MM-dd";
        } else if (datetime.matches(hourRegex)) {
            pattern = "yyyy-MM-dd HH";
        } else if (datetime.matches(minRegex)) {
            pattern = "yyyy-MM-dd HH:mm";
        } else {
            pattern = YYYY_MM_DD_HH_MM_SS_DASH;
        }
        DateTimeFormatter dtf = DateTimeFormat.forPattern(pattern);
        DateTime dt = DateTime.parse(datetime, dtf);
        return dt.toDate();
    }

    /**
     * 计算俩个时间之间的分钟数
     * chenyg 2017年8月3日 上午11:22:21
     *
     * @param start
     * @param end
     * @return
     */
    public static int getDurationMinutes(Date start, Date end) {
        Minutes diff = Minutes.minutesBetween(new DateTime(start), new DateTime(end));
        return diff.getMinutes();
    }

    /**
     * 计算俩个时间之间的秒数
     * MaXin 2019年8月5日 上午11:22:21
     *
     * @param start
     * @param end
     * @return
     */
    public static int getDurationSeconds(Date start, Date end) {
        Seconds diff = Seconds.secondsBetween(new DateTime(start), new DateTime(end));
        return diff.getSeconds();
    }

    /**
     * 计算两个时间之间的年数
     *
     * @return
     */
    public static int getDurationYears(Date start, Date end) {
        Years diff = Years.yearsBetween(new DateTime(start), new DateTime(end));
        return diff.getYears();
    }

    /**
     * 获取偏移日期
     *
     * @param offset
     * @return
     */
    public static Date getOffsetDate(int offset) {

        SimpleDateFormat dft = new SimpleDateFormat("yyyy-MM-dd");
        Date beginDate = new Date();
        Calendar date = Calendar.getInstance();
        date.setTime(beginDate);
        date.set(Calendar.DATE, date.get(Calendar.DATE) + offset);
        Date endDate = null;
        try {
            endDate = dft.parse(dft.format(date.getTime()));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return endDate;
    }

    /**
     * 计算两个时间之间的月数
     *
     * @return
     */
    public static int getDurationMonths(Date start, Date end) {
        Months diff = Months.monthsBetween(new DateTime(start), new DateTime(end));
        return diff.getMonths();
    }

    /**
     * 计算两个时间之间的周数
     */
    public static int getDurationWeeks(Date start, Date end) {
        Weeks diff = Weeks.weeksBetween(new DateTime(start), new DateTime(end));
        return diff.getWeeks();
    }

    /**
     * 计算两个时间之间的天数
     *
     * @return
     */
    public static int getDurationDays(Date start, Date end) {
        Days diff = Days.daysBetween(new DateTime(start), new DateTime(end));
        return diff.getDays();
    }

    /**
     * 计算两个时间之间的小时数
     *
     * @return
     */
    public static int getDurationHours(Date start, Date end) {
        Hours diff = Hours.hoursBetween(new DateTime(start), new DateTime(end));
        return diff.getHours();
    }

    /**
     * 计算某个时间段中的时间  hh小时mm分钟
     * chenyg 2017年8月3日 上午11:35:43
     *
     * @param start
     * @param end
     * @return
     */
    public static String getDurationHourAndMinutes(Date start, Date end) {
        Minutes diff = Minutes.minutesBetween(new DateTime(start), new DateTime(end));
        int minutes = diff.getMinutes();
        int hour = 0;
        int day = 0;
        if (minutes >= 24 * 60) {
            day = minutes / (24 * 60);
            minutes = minutes - (day * 24 * 60);
        }
        if (minutes >= 60) {
            hour = minutes / 60;
            minutes = minutes - (hour * 60);
        }

        return day + "天" + hour + "时" + minutes + "分";
    }

    /**
     * 将Date转换为String
     * ZengXiaoLiang 2016年11月28日 下午1:28:01
     *
     * @param date
     * @param dataPattern 使用HigoDatetimeUtils.YYYY_MM_DD_HH_MM_SS_DASH
     * @return
     */
    public static String date2String(Date date, String dataPattern) {
        if (date != null) {
            return new DateTime(date).toString(dataPattern);
        } else {
            return "";
        }
    }

    /**
     * @param date
     * @return
     */
    public static String date2BrokenString(Date date) {
        if (date != null) {
            return new DateTime(date).toString(JodaDateUtil.YYYYMMDD_HH_MM_SS_DASH_BROKEN);
        } else {
            return "";
        }
    }

    /**
     * 根据日期计算星期几
     */
    public static String getWeek(Date date) {
        switch (DateUtil.getDayOfWeek(date)) {
            case 1:
                return "星期一";
            case 2:
                return "星期二";
            case 3:
                return "星期三";
            case 4:
                return "星期四";
            case 5:
                return "星期五";
            case 6:
                return "星期六";
            case 7:
                return "星期日";
            default:
                return null;
        }
    }

    /**
     * 根据开始结束时间，获取yyyy-MM-dd日期数组
     */
    public static List<String> getDayArrays(Date startDate, Date endDate) {
        List<String> times = new ArrayList<>();
        while (startDate.before(endDate)) {
            String start = JodaDateUtil.date2String(startDate, "yyyy-MM-dd");
            times.add(start);
            startDate = DateUtil.addDays(startDate, 1);
        }

        String end = JodaDateUtil.date2String(endDate, "yyyy-MM-dd");
        if (!times.contains(end)) {
            times.add(end);
        }
        return times;
    }

    /**
     * 根据开始结束时间，获取yyyy-week数组 一年的第几周
     */
    public static List<String> getWeekArrays(Date startDate, Date endDate) {
        List<String> times = new ArrayList<>();

        while (startDate.before(endDate)) {
            String start = JodaDateUtil.date2String(startDate, "yyyy") + "-" + DateUtil.getWeekOfYear(startDate);
            times.add(start);
            startDate = DateUtil.addWeeks(startDate, 1);
        }

        String end = JodaDateUtil.date2String(endDate, "yyyy") + "-" + DateUtil.getWeekOfYear(endDate);
        if (!times.contains(end)) {
            times.add(end);
        }
        return times;
    }

    /**
     * 根据开始结束时间，获取yyyy-MM 月份 数组
     */
    public static List<String> getMonthArrays(Date startDate, Date endDate) {
        List<String> times = new ArrayList<>();
        while (startDate.before(endDate)) {
            String start = JodaDateUtil.date2String(startDate, "yyyy-MM");
            times.add(start);
            startDate = DateUtil.addMonths(startDate, 1);
        }

        String end = JodaDateUtil.date2String(endDate, "yyyy-MM");
        if (!times.contains(end)) {
            times.add(end);
        }
        return times;
    }

    /**
     * 根据开始结束时间，获取yyyy-season 季度数组 一年的第几季度
     */
    public static List<String> getSeasonArrays(Date startDate, Date endDate) {
        List<String> times = new ArrayList<>();
        while (startDate.before(endDate)) {
            String start = JodaDateUtil.date2String(startDate, "yyyy") + "-" + JodaDateUtil.getSeason(startDate);
            if (!times.contains(start)) {
                times.add(start);
            }
            startDate = DateUtil.addMonths(startDate, 1);
        }

        String end = JodaDateUtil.date2String(endDate, "yyyy") + "-" + JodaDateUtil.getSeason(endDate);
        if (!times.contains(end)) {
            times.add(end);
        }
        return times;
    }

    /**
     * 根据开始结束时间，获取yyyy 年度数组
     */
    public static List<String> getYearArrays(Date startDate, Date endDate) {
        List<String> times = new ArrayList<>();
        while (startDate.before(endDate)) {
            String start = JodaDateUtil.date2String(startDate, "yyyy");
            if (!times.contains(start)) {
                times.add(start);
            }
            startDate = DateUtil.addMonths(startDate, 12);
        }

        String end = JodaDateUtil.date2String(endDate, "yyyy");
        if (!times.contains(end)) {
            times.add(end);
        }
        return times;
    }

    /**
     * 判断置顶日期是一年中的第几季
     */
    public static int getSeason(Date date) {
        String month = JodaDateUtil.date2String(date, "MM");
        switch (month) {
            case "01":
                return 1;
            case "02":
                return 1;
            case "03":
                return 1;
            case "04":
                return 2;
            case "05":
                return 2;
            case "06":
                return 2;
            case "07":
                return 3;
            case "08":
                return 3;
            case "09":
                return 3;
            case "10":
                return 4;
            case "11":
                return 4;
            case "12":
                return 4;
            default:
                return 1;
        }
    }
//    public static void main(String[] args) {
//        Date start = JodaDateUtil.parseStr2Date("2018-11-01");
//        Date end = JodaDateUtil.parseStr2Date("2019-01-25");
////        System.out.println(DateUtil.getWeekOfYear(JodaDateUtil.parseStr2Date("2019-01-05")));
////        System.out.println(JodaDateUtil.getDayArrays(start, end));
////        System.out.println(JodaDateUtil.getMonthArrays(start, end));
////        System.out.println(JodaDateUtil.getSeasonArrays(start, end));
//        System.out.println(JodaDateUtil.getYearArrays(start,end));
//    }

    /**
     * 取时间段范围内的各个时间点
     *
     * @param dBegin
     * @param dEnd
     * @return
     */
    public static List<String> findDates(Date dBegin, Date dEnd) {
        List<String> lDate = new ArrayList<String>();
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
        lDate.add(sd.format(dBegin));
        Calendar calBegin = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calBegin.setTime(dBegin);
        Calendar calEnd = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calEnd.setTime(dEnd);
        // 测试此日期是否在指定日期之后
        while (dEnd.after(calBegin.getTime())) {
            // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
            calBegin.add(Calendar.DAY_OF_MONTH, 1);
            lDate.add(sd.format(calBegin.getTime()));
        }
        return lDate;
    }

    /**
     * 根据开始结束时间得到范围内的日期集合
     *
     * @param dBegin
     * @param dEnd
     * @return
     */
    public static List<Date> listDate(Date dBegin, Date dEnd) {
        List<Date> lDate = new ArrayList<Date>();
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
        lDate.add(dBegin);
        Calendar calBegin = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calBegin.setTime(dBegin);
        Calendar calEnd = Calendar.getInstance();
        // 使用给定的 Date 设置此 Calendar 的时间
        calEnd.setTime(dEnd);
        // 测试此日期是否在指定日期之后
        while (dEnd.after(calBegin.getTime())) {
            // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
            calBegin.add(Calendar.DAY_OF_MONTH, 1);
            lDate.add(calBegin.getTime());
        }
        return lDate;
    }

    public static Date localDate2Date(java.time.LocalDate localDate) {
        if(null == localDate) {
            return null;
        }
        ZonedDateTime zonedDateTime = localDate.atStartOfDay(ZoneId.systemDefault());
        return Date.from(zonedDateTime.toInstant());
    }

    public static java.time.LocalDateTime date2LocalDate(Date date) {
        java.time.Instant instant = date.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        java.time.LocalDateTime localDateTime = java.time.LocalDateTime.ofInstant(instant, zone);
        return LocalDateTime.from(localDateTime);
    }

}
